package com.hzncc.flowable_diboot.contract.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.diboot.core.binding.Binder;
import com.diboot.core.holder.ThreadLocalHolder;
import com.diboot.core.service.impl.BaseServiceImpl;
import com.diboot.core.util.JSON;
import com.diboot.core.util.S;
import com.diboot.core.vo.LabelValue;
import com.diboot.iam.entity.IamUser;
import com.diboot.iam.service.IamUserService;
import com.diboot.iam.util.IamSecurityUtils;
import com.diboot.tenant.entity.IamTenant;
import com.diboot.tenant.service.IamTenantService;
import com.hzncc.flowable_diboot.contract.entity.*;
import com.hzncc.flowable_diboot.contract.service.*;
import com.hzncc.flowable_diboot.contract.vo.*;
import com.hzncc.flowable_diboot.delivery.entity.DeliveryDetail;
import com.hzncc.flowable_diboot.entity.SalesGroupContent;
import com.hzncc.flowable_diboot.entity.invoicemanage.InvoiceRegister;
import com.hzncc.flowable_diboot.enums.SAPStatusEnum;
import com.hzncc.flowable_diboot.mapper.ContractAuditMapper;
import com.hzncc.flowable_diboot.mapper.DeliveryDetailMapper;
import com.hzncc.flowable_diboot.mapper.SalesContractMapper;
import com.hzncc.flowable_diboot.mapper.invoicemanage.InvoiceRegisterMapper;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAudit;
import com.hzncc.flowable_diboot.project_contracts.mapper.ProjectContractAuditMapper;
import com.hzncc.flowable_diboot.project_contracts.vo.ProjectContractAuditDetailVO;
import com.hzncc.flowable_diboot.project_contracts.vo.ProjectContractItemDetailVO;
import com.hzncc.flowable_diboot.service.SalesGroupContentService;
import com.hzncc.flowable_diboot.util.SapUtil;
import com.sap.conn.jco.JCoException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 销售合同 相关Service实现类
 *
 * @author MyName
 * @version 1.0
 * @date 2024-09-02
 * Copyright © MyCorp
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SalesContractServiceImpl extends BaseServiceImpl<SalesContractMapper, SalesContract> implements SalesContractService {

    private final SapUtil sapUtil;

    private final FieldMappingService fieldMappingService;

    private final ContractAuditMapper contractAuditMapper;

    private final SalesContractExtService salesContractExtService;

    private final SalesContractMrlService salesContractMrlService;

    private final ContractProductService contractProductService;

    private final ProjectContractAuditMapper projectContractAuditMapper;
    private final SalesGroupContentService salesGroupContentService;
    private final IamTenantService iamTenantService;
    private final DeliveryDetailMapper deliveryDetailMapper;
    private final InvoiceRegisterMapper invoiceRegisterMapper;

    @Override
    public String getDeliveryStatusByContractCode(String contractCode) {
        //根据合同编码查询销售合同信息
        LambdaQueryWrapper<SalesContract> salesContractQuery = new LambdaQueryWrapper<>();
        salesContractQuery.eq(SalesContract::getOrderCode, contractCode);
        List<SalesContract> salesContractList = this.getEntityList(salesContractQuery);
        if (CollectionUtils.isEmpty(salesContractList)) {
            return "1";
        }
        // 查询所有销售合同发货明细
        LambdaQueryWrapper<DeliveryDetail> deliveryDetailQuery = new LambdaQueryWrapper<>();
        deliveryDetailQuery.in(DeliveryDetail::getSapContractCode, salesContractList.stream().map(SalesContract::getSapCode).toList())
                .eq(DeliveryDetail::getType, "1").eq(DeliveryDetail::getRegisterType, "1");
        List<DeliveryDetail> deliveryDetails = deliveryDetailMapper.selectList(deliveryDetailQuery);
        if (deliveryDetails == null || deliveryDetails.isEmpty()) { // 未查询到发货明细
            return "1"; // 未发货
        }
        // 统计每个物料发货数量
        Map<String, Long> deliveryCollect = deliveryDetails.stream().collect(Collectors.groupingBy(DeliveryDetail::getMaterialCode, Collectors.summingLong(DeliveryDetail::getQuantity)));
        // 查询未删除的销售合同物料
        LambdaQueryWrapper<SalesContractMrl> salesContractMrlQuery = new LambdaQueryWrapper<>();
        salesContractMrlQuery.in(SalesContractMrl::getSalesContractId, salesContractList.stream().map(SalesContract::getId).toList())
                .eq(SalesContractMrl::getDeletedFlag, false).eq(SalesContractMrl::getPushStatus,true);
        List<SalesContractMrl> mrls = salesContractMrlService.getEntityList(salesContractMrlQuery);
        // 统计每个物料的数量
        Map<String, Long> mrlCollect = mrls.stream().collect(Collectors.groupingBy(SalesContractMrl::getMrlCode, Collectors.summingLong(e -> e.getTargerQty().longValue())));
        // 比较是否全部发货
        for (Map.Entry<String, Long> entry : mrlCollect.entrySet()) {
            Long deliveryLong = deliveryCollect.get(entry.getKey());
            if (deliveryLong == null || deliveryLong < entry.getValue()) {
                return "2";//部分发货
            }
        }
        return "0";
    }

    @Override
    public String getInvoiceStatusByContractCode(String contractCode) {
        //根据合同编码查询销售合同信息
        LambdaQueryWrapper<SalesContract> salesContractQuery = new LambdaQueryWrapper<>();
        salesContractQuery.eq(SalesContract::getOrderCode, contractCode);
        List<SalesContract> salesContractList = this.getEntityList(salesContractQuery);
        if (CollectionUtils.isEmpty(salesContractList)) {
            return "2";
        }
        // 查询销售合同所有开票信息
        LambdaQueryWrapper<InvoiceRegister> invoiceRegisterQuery = new LambdaQueryWrapper<>();
        invoiceRegisterQuery.in(InvoiceRegister::getSapContractCode, salesContractList.stream().map(SalesContract::getSapCode).toList());
        List<InvoiceRegister> invoiceRegisters = invoiceRegisterMapper.selectList(invoiceRegisterQuery);
        // 统计每个销售合同开票金额
        Map<String, BigDecimal> invoiceCollect = invoiceRegisters.stream().collect(Collectors.groupingBy(InvoiceRegister::getSapContractCode, Collectors.reducing(BigDecimal.ZERO, InvoiceRegister::getInvoiceAmount, BigDecimal::add)));
        // 遍历销售合同，判断是否全部开票
        for (SalesContract salesContract : salesContractList) {
            BigDecimal bigDecimal = invoiceCollect.get(salesContract.getSapCode());
            if (bigDecimal == null || bigDecimal.compareTo(new BigDecimal(salesContract.getFixedDiscountAmount())) < 0) {
                return "1";
            }
        }
        return "0";
    }

    /**
     * SAP推送
     *
     * @param id 销售合同id
     * @author 陈广煜
     * @date 2024-09-09
     */
    public void pushSap(String id) throws JCoException {
        // 根据销售合同id获取销售合同视图对象
        SalesContractListVO salesContract = getViewObject(id, SalesContractListVO.class);
        // 根据销售合同是否已有SAP编码确定调用的函数名
        String funStr = "ZRFC_CRM_VBAK_G";
        if (S.isNotBlank(salesContract.getSapCode())) {
            funStr = "ZRFC_CRM_VBAK_UPD";
        }
        // 将销售合同对象转换为JSON字符串，用于SAP推送
        String jsonStr = fieldMappingService.entityToJson(salesContract, "SAP-PUSH");
        // 将JSON字符串转换为Map对象，以便后续处理
        Map<String, Object> param = JSON.toMap(jsonStr);
        // 初始化MRL（物料需求计划）列表
        List<Map<String, Object>> mrlMapList = new ArrayList<>();
        // 遍历销售合同的MRL列表，进行数据处理
        List<SalesContractMrl> mrlList = salesContract.getMrlList();
//        // 检查SAP销售视图是否维护
//        mrlList = checkMrlCanPush(mrlList, salesContract.getSalesOrganization(), salesContract.getDistributionChannel());
        // 遍历MRL列表，将需要推送的MRL数据加入到MRL列表中
        for (int i = 0; i < mrlList.size(); i++) {
            SalesContractMrl e = mrlList.get(i);
            // 只处理有MRL编码的项
            if (S.isNotBlank(e.getMrlCode()) && e.getPushFlag()) {
                Map<String, Object> mrlMap = new HashMap<>();
                mrlMap.put("POSNR", e.getProductName());
                mrlMap.put("MATNR", e.getMrlCode());
                mrlMap.put("ZMENG", e.getTargerQty());
                mrlMap.put("ZFLAG", e.getDeletedFlag() ? "D" : "");
                mrlMapList.add(mrlMap);
            }
        }
        // 调用SAP接口，传入函数名、参数和MRL列表，返回结果Map
        Map<String, String> map = sapUtil.contractCreate(funStr, param, mrlMapList, salesContract.getSapCode());
        // 根据返回结果更新销售合同和相关实体的状态
        String contractProductId = salesContract.getContractProductId();
        if (S.isNotBlank(contractProductId)) {
            ContractProduct contractProduct = contractProductService.getEntity(contractProductId);
            ContractAudit contractAudit = contractAuditMapper.selectById(contractProduct.getContractAuditId());
            contractProduct.setSapContractId(salesContract.getId());
            // 如果SAP推送成功
            if (S.equals(map.get("code"), "S")) {
                salesContract.setSapCode(map.get("contractCode"));
                salesContract.setPushStatus(1); // 成功
                salesContract.setFailureCause("");
                contractAudit.setSapMsg(map.get("msg"));
                // 回写系统合同sap编码
                if (!S.contains(contractAudit.getSapCode(), salesContract.getSapCode())) {
                    contractAudit.setSapCode(S.isBlank(contractAudit.getSapCode()) ? salesContract.getSapCode() : contractAudit.getSapCode() + "," + salesContract.getSapCode());
                }
                // 回写合同项目sap编码
                contractProduct.setSapContractCode(salesContract.getSapCode());
                // 更新sap合同物料推送状态
                mrlList.forEach(e -> {
                    if ((S.isNotBlank(e.getMrlCode()) && e.getPushFlag()) || (!e.getPushStatus() && !e.getPushFlag() && e.getDeletedFlag())) {
                        e.setPushStatus(true);
                    }
                });
                // 判断MRL列表是否全部推送成功
                if (mrlList.stream().allMatch(SalesContractMrl::getPushStatus)) {
                    contractProduct.setSapContractPushStatus("3"); // 全部推送
                } else {
                    contractProduct.setSapContractPushStatus("2"); // 部分推送
                }
            } else {
                // 如果SAP推送失败
                salesContract.setPushStatus(2); // 失败
                salesContract.setFailureCause(map.get("msg"));
                contractAudit.setSapStatus(SAPStatusEnum.FAIL.getCode());
                contractAudit.setSapMsg(map.get("msg"));
                // 更新sap合同物料推送状态
                mrlList.forEach(e -> {
                    if (S.isNotBlank(e.getMrlCode()) && e.getPushFlag()) {
                        e.setPushStatus(false);
                    }
                });
                contractProduct.setSapContractPushStatus("1");
            }
            contractProductService.updateEntity(contractProduct);
            contractAuditMapper.updateById(contractAudit);
            // 更新销售合同和MRL列表
            updateEntity(salesContract);
            salesContractMrlService.updateEntities(mrlList);
            if (S.equals(map.get("code"), "S")) {
                changeSapPushStatus(contractAudit.getId());
            }
        }
        String projectContractId = salesContract.getProjectContractId();
        if (S.isNotBlank(projectContractId)) {
            ProjectContractAudit projectContractAudit = projectContractAuditMapper.selectById(projectContractId);
            // 如果SAP推送成功
            if (S.equals(map.get("code"), "S")) {
                salesContract.setSapCode(map.get("contractCode"));
                salesContract.setPushStatus(1); // 成功
                salesContract.setFailureCause("");
                projectContractAudit.setSapContractCode(salesContract.getSapCode());
                projectContractAudit.setSapMsg(map.get("msg"));
                mrlList.forEach(e -> {
                    if ((S.isNotBlank(e.getMrlCode()) && e.getPushFlag()) || (!e.getPushStatus() && !e.getPushFlag() && e.getDeletedFlag())) {
                        e.setPushStatus(true);
                    }
                });
                projectContractAudit.setSapStatus(mrlList.stream().allMatch(SalesContractMrl::getPushStatus) ? SAPStatusEnum.PUSH_ALL.getCode() : SAPStatusEnum.PARTIAL_PUSH.getCode());
            } else {
                // 如果SAP推送失败
                salesContract.setPushStatus(2); // 失败
                salesContract.setFailureCause(map.get("msg"));
                projectContractAudit.setSapMsg(map.get("msg"));
                projectContractAudit.setSapStatus(SAPStatusEnum.FAIL.getCode());
            }
            projectContractAuditMapper.updateById(projectContractAudit);
            // 更新销售合同和MRL列表
            updateEntity(salesContract);
            salesContractMrlService.updateEntities(mrlList);
        }

    }

    /**
     * 更新SAP推送状态
     *
     * @param id 系统合同id
     */
    private void changeSapPushStatus(String id) {
        List<ContractProduct> entityList = contractProductService.getEntityList(contractProductService.lambdaQuery().eq(ContractProduct::getContractAuditId, id));
        UpdateWrapper<ContractAudit> updateWrapper = new UpdateWrapper<>();
        if (entityList.stream().allMatch(e -> S.equals("3", e.getSapContractPushStatus()))) { // 全部推送
            updateWrapper.lambda().set(ContractAudit::getSapStatus, SAPStatusEnum.PUSH_ALL.getCode()).eq(ContractAudit::getId, id);
        } else if (entityList.stream().anyMatch(e -> !S.equals("1", e.getSapContractPushStatus()))) { // 部分推送
            updateWrapper.lambda().set(ContractAudit::getSapStatus, SAPStatusEnum.PARTIAL_PUSH.getCode()).eq(ContractAudit::getId, id);
        }
        contractAuditMapper.update(updateWrapper);
    }

    /**
     * SAP合同取消
     *
     * @param id
     * @throws JCoException
     * @author 陈广煜
     * @date 2024-09-09
     */
    public void cancelSap(String id) throws JCoException {
        ThreadLocalHolder.setIgnoreInterceptor();
        SalesContractListVO salesContract = getViewObject(id, SalesContractListVO.class);
        List<SalesContractMrl> mrlList = salesContract.getMrlList();
        List<Map<String, Object>> mrlMapList = new ArrayList<>();
        for (int i = 0; i < mrlList.size(); i++) {
            SalesContractMrl e = mrlList.get(i);
            Map<String, Object> mrlMap = new HashMap<>();
            mrlMap.put("POSNR", i + 1);
            mrlMap.put("MATNR", e.getMrlCode());
            mrlMap.put("ZMENG", e.getTargerQty());
            mrlMap.put("ZFLAG", "D");
            mrlMapList.add(mrlMap);
        }
        ThreadLocalHolder.setIgnoreInterceptor();
        ContractProduct contractProduct = contractProductService.getEntity(salesContract.getContractProductId());
        ThreadLocalHolder.setIgnoreInterceptor();
        ContractAudit contractAudit = contractAuditMapper.selectById(contractProduct.getContractAuditId());
        Map<String, String> map = sapUtil.contractCancel("ZRFC_CRM_VBAK_CANCEL", mrlMapList, salesContract.getSapCode());
        if (S.equals(map.get("code"), "S")) {
            salesContract.setPushStatus(1); // 成功
            salesContract.setIsCancel(true);
            contractAudit.setSapStatus(SAPStatusEnum.SUCCESS.getCode());
            contractAudit.setSapMsg(map.get("msg"));
            contractProduct.setSapContractCode(salesContract.getSapCode());
        } else {
            salesContract.setPushStatus(2); // 失败
            salesContract.setFailureCause(map.get("msg"));
            contractAudit.setSapStatus(SAPStatusEnum.FAIL.getCode());
            contractAudit.setSapMsg(map.get("msg"));
        }
        ThreadLocalHolder.setIgnoreInterceptor();
        updateEntity(salesContract);
        ThreadLocalHolder.setIgnoreInterceptor();
        contractProductService.updateEntity(contractProduct);
        ThreadLocalHolder.setIgnoreInterceptor();
        contractAuditMapper.updateById(contractAudit);
    }

    /**
     * 从合同中获取
     *
     * @param salesContractListVO
     * @param contractDetail
     * @param productListVO
     * @return
     * @author 陈广煜
     * @date 2025-02-14
     */
    private SalesContractListVO fromContract(SalesContractListVO salesContractListVO, ContractAuditVO contractDetail, ContractProductListVO productListVO) {
        salesContractListVO = salesContractListVO == null ? new SalesContractListVO() : salesContractListVO;
        salesContractListVO.setTenantId(contractDetail.getTenantId())
                .setOrderCode(contractDetail.getContractCode()) // 采购订单编号
                .setSoldToParty(contractDetail.getCustomerId()) // 售达方
                .setSoldToPartySapCode(contractDetail.getSapNo())
                .setOrderDate(contractDetail.getCreateTime())
                .setBusinessDept(contractDetail.getSignDept()) // 业务部门
                .setContractProductId(productListVO.getId())
                .setRecipient(contractDetail.getCustomerId()) // 送达方
                .setRecipientSapCode(contractDetail.getSapNo())
                .setOrderItem(productListVO.getProductCode())  // 订购项目
                .setOrderModel(productListVO.getProductType()) // 订购型号
                .setOrderQuantity(String.valueOf(productListVO.getProductCount())) // 订购数量
                .setSystemChannel(productListVO.getChannelNum()) // 系统通道
                .setDeliveryTime(contractDetail.getDeliveryDate()) // 交货时间
                .setFixedDiscountAmount(productListVO.getContractPrice().toString()) // 固定折扣金额
                .setPaymentMethod(contractDetail.getSettlementMethod()) // 付款方式
                .setQualityCondition(getQualityCondition(contractDetail.getContractExtVO() == null ? null : contractDetail.getContractExtVO().getWarrantyMonths()))
                .setTextOfAttachment(S.isBlank(contractDetail.getContractInfoVO().getAttachmentFileDesc()) ? "无" : contractDetail.getContractInfoVO().getAttachmentFileDesc())
                .setBusinessModel(contractDetail.getBusinessModel())
                .setDistributionChannel(contractDetail.getDistributionChannel()) // 分销渠道
                .setProductGroup(contractDetail.getProductGroup()) // 产品组
                .setSalesOrganization(contractDetail.getSalesOrg()) // 销售组织
                .setSalesTerritory(S.equals(contractDetail.getBusinessModel(),"IS") ? null : contractDetail.getSalesDept())
                .setProductNature(contractDetail.getProductType())
        ;
        // 重新计算未收款金额
        String amountNotReceived = new BigDecimal(salesContractListVO.getFixedDiscountAmount() == null ? "0" : salesContractListVO.getFixedDiscountAmount())
                .subtract(new BigDecimal(salesContractListVO.getAmountReceived() == null ? "0" : salesContractListVO.getAmountReceived()))
                .toString();
        salesContractListVO.setAmountNotReceived(amountNotReceived);
        SalesContractExtListVO ext = salesContractListVO.getExt();
        if (ext == null) {
            ext = new SalesContractExtListVO();
        }
        ext.setSupportingMachineTool(S.isBlank(productListVO.getMachineType()) ? StrUtil.nullToDefault(productListVO.getProductCode(), "") + "/" + StrUtil.nullToDefault(productListVO.getProductType(), "") : productListVO.getMachineType()); // 配套机床型号
//        ext.setSalesDepartmentLabel(salesContractListVO.getSalesTerritoryLabel());
//        ext.setSalesDepartment(salesContractListVO.getSalesTerritory());
        ext.setContractType("YSR");
        ext.setContractTypeLabel(new LabelValue("标准合同", "YSR"));
        salesContractListVO.setExt(ext);
        return salesContractListVO;
    }

    /**
     * 合同信息
     *
     * @param contractDetail
     * @param productListVO
     * @return
     */
    @Override
    public SalesContractListVO getSalesContract(ContractAuditVO contractDetail, ContractProductListVO productListVO) {
        SalesContractListVO salesContractListVO = fromContract(null, contractDetail, productListVO);
        salesContractListVO.setSalesEmployee(IamSecurityUtils.getCurrentUserId()) // 销售员工
                .setSalesEmployeeNumber(((IamUser) IamSecurityUtils.getCurrentUser()).getUserNum())
                .setContractType("1");
        List<SalesContractMrl> mrlList = new ArrayList<>();
        if (productListVO.getContractProductMaterialVOList() != null) {
            for (ContractProductMaterialVO productMrl : productListVO.getContractProductMaterialVOList()) {
                SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                        .setMrlDesc(productMrl.getMaterialDesc())
                        .setAmount(BigDecimal.ZERO)
                        .setQtyUnshipped(new BigDecimal(productMrl.getMaterialCount()))
                        .setQtyShipped(BigDecimal.ZERO)
                        .setRemark(productMrl.getRemark())
                        .setPushFlag(true)
                        .setDeletedFlag(false)
                        .setTargerQty(new BigDecimal(productMrl.getMaterialCount()))
                        .setProductName(String.valueOf(productMrl.getRowNum()));
                mrlList.add(mrl);
            }
        }
        checkMrlCanPush(mrlList, salesContractListVO.getSalesOrganization(), salesContractListVO.getDistributionChannel());
        salesContractListVO.setMrlList(mrlList);
        Binder.bindRelations(salesContractListVO);
        return salesContractListVO;
    }

    /**
     * 质保条件
     *
     * @param warrantyMonths
     * @return
     */
    private String getQualityCondition(Long warrantyMonths) {
        if (warrantyMonths == null) {
            return null;
        }
        int flag = warrantyMonths.intValue();
        switch (flag) {
            case 12:
                return "A01";
            case 24:
                return "A10";
            case 36:
                return "A20";
            case 60:
                return "A30";
        }
        return null;
    }

    /**
     * 推送合同
     *
     * @param salesContract
     * @throws JCoException
     */
    @Override
    public void pushSap(SalesContractListVO salesContract) throws JCoException {
        createOrUpdateEntity(salesContract);
        salesContractExtService.createOrUpdateEntity(salesContract.getExt().setSalesContractId(salesContract.getId()));
        salesContract.getMrlList().forEach(e -> e.setSalesContractId(salesContract.getId()));
        salesContractMrlService.createOrUpdateEntities(salesContract.getMrlList());
        pushSap(salesContract.getId());
    }

    /**
     * 根据合同产品id获取销售合同
     *
     * @param contractProductId
     * @return
     */
    @Override
    public SalesContractListVO getSalesContract(String contractProductId) {
        ContractProductListVO productListVO = contractProductService.getViewObject(contractProductId, ContractProductListVO.class);
        ContractAudit contractDetail = contractAuditMapper.selectById(productListVO.getContractAuditId());
        ContractAuditVO contractAuditVO = Binder.convertAndBindRelations(contractDetail, ContractAuditVO.class);
        QueryWrapper<SalesContract> qw = new QueryWrapper<>();
        qw.lambda().eq(SalesContract::getSapCode, productListVO.getSapContractCode()).or().eq(SalesContract::getContractProductId, contractProductId);
        SalesContract salesContract = getSingleEntity(qw);
        if (salesContract != null) {
            salesContract.setContractProductId(productListVO.getId());
            SalesContractListVO salesContractListVO = Binder.convertAndBindRelations(salesContract, SalesContractListVO.class);
            salesContractListVO = fromContract(salesContractListVO, contractAuditVO, productListVO);
            // 销售合同物料 过滤已推送已删除的物料
            List<SalesContractMrl> mrlList = salesContractListVO.getMrlList().stream().filter(e -> !(e.getPushStatus() && e.getDeletedFlag())).toList();
            Map<String, SalesContractMrl> salesMrlMap = mrlList.stream().collect(Collectors.toMap(SalesContractMrl::getProductName, e -> e));
            // 合同物料
            List<ContractProductMaterialVO> contractMrls = productListVO.getContractProductMaterialVOList();
            Map<String, ContractProductMaterialVO> contractMrlMap = contractMrls.stream().collect(Collectors.toMap(k -> k.getRowNum() + "", e -> e));
            // 待推送的物料 合同中新增以及变更的物料和sap合同中未推送的物料
            List<SalesContractMrl> push = new ArrayList<>();
            for (Map.Entry<String, ContractProductMaterialVO> entry : contractMrlMap.entrySet()) {
                String key = entry.getKey();
                ContractProductMaterialVO productMrl = entry.getValue();
                SalesContractMrl salesContractMrl = salesMrlMap.get(key);
                // 新增物料
                if (salesContractMrl == null) {
                    SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                            .setMrlDesc(productMrl.getMaterialDesc())
                            .setAmount(BigDecimal.ZERO)
                            .setQtyUnshipped(new BigDecimal(productMrl.getMaterialCount()))
                            .setQtyShipped(BigDecimal.ZERO)
                            .setRemark(productMrl.getRemark()).setPushFlag(true).setDeletedFlag(false)
                            .setProductName(StrUtil.toStringOrNull(productMrl.getRowNum()))
                            .setTargerQty(new BigDecimal(productMrl.getMaterialCount()));
                    push.add(mrl);
                } else if (!Objects.equals(productMrl.getMaterialCode(), salesContractMrl.getMrlCode())
                        || !Objects.equals(productMrl.getMaterialDesc(), salesContractMrl.getMrlDesc())
                        || !Objects.equals(productMrl.getMaterialCount(), salesContractMrl.getTargerQty().longValue())
                        || !salesContractMrl.getPushStatus()) { // 变更或未推送物料
                    SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                            .setMrlDesc(productMrl.getMaterialDesc())
                            .setAmount(BigDecimal.ZERO)
                            .setQtyUnshipped(new BigDecimal(productMrl.getMaterialCount()))
                            .setQtyShipped(BigDecimal.ZERO)
                            .setRemark(productMrl.getRemark()).setPushFlag(true).setDeletedFlag(false)
                            .setProductName(StrUtil.toStringOrNull(productMrl.getRowNum()))
                            .setTargerQty(new BigDecimal(productMrl.getMaterialCount()));
                    mrl.setId(salesContractMrl.getId());
                    push.add(mrl);
                }
            }
            // 删除的物料
            for (SalesContractMrl salesContractMrl : mrlList) {
                ContractProductMaterialVO contractProductMaterialVO = contractMrlMap.get(salesContractMrl.getProductName());
                if (contractProductMaterialVO == null) {
                    salesContractMrl.setDeletedFlag(true);
                    salesContractMrl.setPushFlag(true);
                    push.add(salesContractMrl);
                }
            }
            // 检查SAP销售视图是否维护
            checkMrlCanPush(push, salesContractListVO.getSalesOrganization(), salesContractListVO.getDistributionChannel());
            salesContractListVO.setMrlList(push);
            return salesContractListVO;
        }
        if (contractAuditVO.getContractProductVOList() == null) {
            contractAuditVO.setContractProductVOList(new ArrayList<>());
        }
        ContractAuditCancelListVO contractAuditCancelVO = contractAuditVO.getContractAuditCancelVO();
        if (contractAuditCancelVO != null) {
            contractAuditCancelVO.setCustomerId(contractAuditVO.getCustomerId());
            contractAuditCancelVO.setCustomerName(contractAuditVO.getCustomerName());
        }
        for (ContractProductListVO contractProductListVO : contractAuditVO.getContractProductVOList()) {
            contractProductListVO.setProductDesc(productListVO.getMachineType() + " " + productListVO.getProductType());
        }
        return getSalesContract(contractAuditVO, productListVO);
    }

    @Override
    public SalesContractListVO getSalesContractFormProject(String projectContractId) {
        ProjectContractAudit contractAudit = projectContractAuditMapper.selectById(projectContractId);
        ProjectContractAuditDetailVO contractDetail = Binder.convertAndBindRelations(contractAudit, ProjectContractAuditDetailVO.class);
        QueryWrapper<SalesContract> qw = new QueryWrapper<>();
        qw.lambda().eq(SalesContract::getOrderCode, contractAudit.getContractCode());
        SalesContract salesContract = getSingleEntity(qw);
        if (salesContract != null) {
            SalesContractListVO salesContractListVO = Binder.convertAndBindRelations(salesContract, SalesContractListVO.class);
            salesContractListVO = fromContract(salesContractListVO, contractDetail);
            // 销售合同物料 过滤已推送已删除的物料
            List<SalesContractMrl> mrlList = salesContractListVO.getMrlList().stream().filter(e -> !(e.getPushStatus() && e.getDeletedFlag())).toList();
            Map<String, SalesContractMrl> salesMrlMap = mrlList.stream().collect(Collectors.toMap(SalesContractMrl::getProductName, e -> e));
            // 合同物料
            List<ProjectContractItemDetailVO> contractMrls = contractDetail.getContractItemList();
            Map<String, ProjectContractItemDetailVO> contractMrlMap = contractMrls.stream().collect(Collectors.toMap(k -> k.getSerialNumber() + "", e -> e));
            // 待推送的物料 合同中新增以及变更的物料和sap合同中未推送的物料
            List<SalesContractMrl> push = new ArrayList<>();
            for (Map.Entry<String, ProjectContractItemDetailVO> entry : contractMrlMap.entrySet()) {
                String key = entry.getKey();
                ProjectContractItemDetailVO productMrl = entry.getValue();
                SalesContractMrl salesContractMrl = salesMrlMap.get(key);
                // 新增物料
                if (salesContractMrl == null) {
                    SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                            .setMrlDesc(productMrl.getEquipmentName())
                            .setAmount(BigDecimal.ZERO)
                            .setQtyUnshipped(productMrl.getQuantity())
                            .setQtyShipped(BigDecimal.ZERO)
                            .setRemark(productMrl.getRemarks()).setPushFlag(true).setDeletedFlag(false)
                            .setProductName(StrUtil.toStringOrNull(productMrl.getSerialNumber()))
                            .setTargerQty(productMrl.getQuantity());
                    push.add(mrl);
                } else if (!Objects.equals(productMrl.getMaterialCode(), salesContractMrl.getMrlCode())
                        || !Objects.equals(productMrl.getEquipmentName(), salesContractMrl.getMrlDesc())
                        || !NumberUtil.equals(productMrl.getQuantity(), salesContractMrl.getTargerQty())
                        || !salesContractMrl.getPushStatus()) { // 变更或未推送物料
                    SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                            .setMrlDesc(productMrl.getEquipmentName())
                            .setAmount(BigDecimal.ZERO)
                            .setQtyUnshipped(productMrl.getQuantity())
                            .setQtyShipped(BigDecimal.ZERO)
                            .setRemark(productMrl.getRemarks()).setPushFlag(true).setDeletedFlag(false)
                            .setProductName(StrUtil.toStringOrNull(productMrl.getSerialNumber()))
                            .setTargerQty(productMrl.getQuantity());
                    mrl.setId(salesContractMrl.getId());
                    push.add(mrl);
                }
            }
            // 删除的物料
            for (SalesContractMrl salesContractMrl : mrlList) {
                ProjectContractItemDetailVO contractProductMaterialVO = contractMrlMap.get(salesContractMrl.getProductName());
                if (contractProductMaterialVO == null) {
                    salesContractMrl.setDeletedFlag(true);
                    salesContractMrl.setPushFlag(true);
                    push.add(salesContractMrl);
                }
            }
            // 检查SAP销售视图是否维护
            checkMrlCanPush(push, salesContractListVO.getSalesOrganization(), salesContractListVO.getDistributionChannel());
            salesContractListVO.setMrlList(push);
            return salesContractListVO;
        } else {
            return getSalesContract(contractDetail);
        }
    }

    /**
     * 从合同中获取数据
     *
     * @param salesContractListVO
     * @param projectContractAudit
     * @return
     * @author 陈广煜
     * @date 2025-02-14
     */
    public SalesContractListVO fromContract(SalesContractListVO salesContractListVO, ProjectContractAuditDetailVO projectContractAudit) {
        if (projectContractAudit.getBusinessDept() == null) {
            switch (projectContractAudit.getBusinessModel()) {
                case "CNC"-> projectContractAudit.setBusinessDept("数控系统事业部");
                case "IS"-> projectContractAudit.setBusinessDept("国际事业部");
                case "IPL"-> projectContractAudit.setBusinessDept("红外事业部");
                case "SCC"-> projectContractAudit.setBusinessDept("重大专项事业部");
                default-> projectContractAudit.setBusinessDept("");
            }
        }
        salesContractListVO = salesContractListVO == null ? new SalesContractListVO() : salesContractListVO;
        salesContractListVO.setTenantId(projectContractAudit.getTenantId())
                .setOrderCode(projectContractAudit.getContractCode()) // 采购订单编号
                .setSoldToParty(projectContractAudit.getCustomerId()) // 售达方
                .setSoldToPartySapCode(projectContractAudit.getCustomerSapNo())
                .setOrderDate(projectContractAudit.getCreateTime())
                .setBusinessDept(projectContractAudit.getBusinessDept()) // 业务部门
                .setProjectContractId(projectContractAudit.getId())
                .setRecipient(projectContractAudit.getCustomerId()) // 送达方
                .setRecipientSapCode(projectContractAudit.getCustomerSapNo())
                .setBusinessModel(projectContractAudit.getBusinessModel()) // 业务板块
                .setSalesTerritory(projectContractAudit.getSalesTerritory())
                .setFixedDiscountAmount(projectContractAudit.getProjectContractAmount().getContractProjectSaleTotal().toString()) // 固定折扣金额
                .setProductNature("1"); // 产品性质
        // 重新计算未收款金额
        String amountNotReceived = new BigDecimal(salesContractListVO.getFixedDiscountAmount() == null ? "0" : salesContractListVO.getFixedDiscountAmount())
                .subtract(new BigDecimal(salesContractListVO.getAmountReceived() == null ? "0" : salesContractListVO.getAmountReceived()))
                .toString();
        salesContractListVO.setAmountNotReceived(amountNotReceived);
        SalesContractExtListVO ext = salesContractListVO.getExt();
        if (ext == null) {
            ext = new SalesContractExtListVO();
        }
//        ext.setSalesDepartmentLabel(salesContractListVO.getSalesTerritoryLabel());
//        ext.setSalesDepartment(salesContractListVO.getSalesTerritory());
        ext.setContractType("YSR");
        ext.setContractTypeLabel(new LabelValue("标准合同", "YSR"));
        salesContractListVO.setExt(ext);
        return salesContractListVO;
    }

    public SalesContractListVO getSalesContract(ProjectContractAuditDetailVO projectContractAudit) {
        IamTenant tenant = iamTenantService.getEntity(IamSecurityUtils.getCurrentTenantId());
        String customerId = projectContractAudit.getCustomerId();
        QueryWrapper<SalesGroupContent> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SalesGroupContent::getSapCustomerId, customerId).eq(SalesGroupContent::getSalesGroup, tenant.getOrgId());
        List<SalesGroupContent> salesGroupContents = salesGroupContentService.getEntityList(queryWrapper);
        SalesContractListVO salesContractListVO = fromContract(null, projectContractAudit);
        if (salesGroupContents != null && !salesGroupContents.isEmpty()) {
            salesContractListVO.setSalesOrganization(salesGroupContents.get(0).getSalesGroup());
            salesContractListVO.setDistributionChannel(salesGroupContents.get(0).getDistributeChannel());
            salesContractListVO.setProductGroup(salesGroupContents.get(0).getProductionGroup());
        }
        salesContractListVO.setContractType("2") // // 合同类型 系统类/项目类
                .setSalesEmployee(projectContractAudit.getSaler()) // 销售员工
                .setSalesEmployeeNumber(projectContractAudit.getSalerNum());
        List<SalesContractMrl> mrlList = new ArrayList<>();
        for (ProjectContractItemDetailVO productMrl : projectContractAudit.getContractItemList()) {
            SalesContractMrl mrl = new SalesContractMrl().setMrlCode(productMrl.getMaterialCode())
                    .setMrlDesc(productMrl.getEquipmentName())
//                    .setAmount(BigDecimal.ZERO)
                    .setPushFlag(true)
                    .setDeletedFlag(false)
                    .setProductName(StrUtil.toStringOrNull(productMrl.getSerialNumber()))
                    .setTargerQty(productMrl.getQuantity());
            mrlList.add(mrl);
        }
        // 检查SAP销售视图是否维护
        checkMrlCanPush(mrlList, salesContractListVO.getSalesOrganization(), salesContractListVO.getDistributionChannel());
        salesContractListVO.setMrlList(mrlList);
        Binder.bindRelations(salesContractListVO);
        return salesContractListVO;
    }

    /**
     * 校验是否已全部推送
     *
     * @param id 项目合同id
     * @return true 已全部推送 false 未全部推送
     */
    @Override
    public Boolean checkSap(String id) {
        LambdaQueryWrapper<SalesContract> query = new LambdaQueryWrapper<>();
        query.eq(SalesContract::getContractProductId, id);
        SalesContract entity = this.getSingleEntity(query);
        if (entity == null) {
            return false;
        }
        LambdaQueryChainWrapper<SalesContractMrl> mrlQuery = salesContractMrlService.lambdaQuery().eq(SalesContractMrl::getSalesContractId, entity.getId());
        List<SalesContractMrl> entityList = salesContractMrlService.getEntityList(mrlQuery);
        return entityList.stream().allMatch(SalesContractMrl::getPushStatus);
    }

    /**
     * 检查物料能否推送
     *
     * @param mrlList 待推送物料
     * @return
     */
    @Override
    public List<SalesContractMrl> checkMrlCanPush(List<SalesContractMrl> mrlList, String salesOrg, String disChannel) {
        try {
            if (mrlList == null || mrlList.stream().noneMatch(SalesContractMrl::getPushFlag)) {
                return mrlList;
            }
            Map<String, String> mrlStat = sapUtil.checkMrlCanPush(mrlList.stream().filter(SalesContractMrl::getPushFlag).map(SalesContractMrl::getMrlCode).toList(), salesOrg, disChannel);
            // 遍历物料列表，物料状态为‘X’才能推送
            for (SalesContractMrl mrl : mrlList) {
                mrl.setPushFlag("X".equals(mrlStat.get(mrl.getMrlCode())));
                mrl.setPushable(mrl.getPushFlag());
            }
        } catch (JCoException e) {
            log.error("sap检查物料推送失败", e);
            throw new RuntimeException(e);
        }
        return mrlList;
    }

    /**
     * 批量推送sap
     *
     * @param ids 系统合同项目id
     * @throws JCoException
     */
    @Override
    public void batchPushSap(List<String> ids) throws JCoException {
        for (String id : ids) {
            SalesContractListVO salesContract = this.getSalesContract(id);
            pushSap(salesContract);
        }
    }

    @Override
    public void updateRelatedField(String id) {
        QueryWrapper<ContractProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, id);
        List<ContractProduct> entityList = contractProductService.getEntityList(queryWrapper);
        if (entityList == null) {
            return;
        }
        for (ContractProduct contractProduct : entityList) {
            UpdateWrapper<SalesContract> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(SalesContract::getContractProductId, contractProduct.getId()).eq(SalesContract::getId, contractProduct.getSapContractId());
            update(updateWrapper);
        }
    }
}